﻿#region copyright
//<copyright>
// Copyright(C) 2012 TrackerRealm Corporation
// This file is part of the open source project - Jazz. http://jazz.codeplex.com
// 
// Jazz is open software: you can redistribute it and/or modify it 
// under the terms of the GNU Affero General Public License (AGPL) as published by 
// the Free Software Foundation, version 3 of the License.
// 
// Jazz is distributed in the hope that it will be useful, 
// but WITHOUT ANY WARRANTY; without even the implied warranty 
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
//  See the GNU Affero General Public License (AGPL) for more details.
// 
// You should have received a copy of the GNU General Public 
// License along with Jazz.  If not, see <http://www.gnu.org/licenses/>.
//
// REMOVAL OF THIS NOTICE IS VIOLATION OF THE COPYRIGHT. 
//</copyright>
#endregion
using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using TrackerRealm.Jazz.Client;
using TrackerRealm.Jazz.Common;
using PostSharp.Extensibility;
using TrackerRealm.Jazz.Json;
using TrackerRealm.Jazz.JsonSpecialized;
using KellermanSoftware.CompareNetObjects;
using System.Runtime.Serialization;
using TrackerRealm.Jazz.Client.Custom;

namespace JazzClientTest
{
    /// <summary>
    /// 
    /// </summary>
    [TestClass]
    public class JsonSerializationTests
    {

        #region SerializeAndRestore
        /// <summary>
        /// Demonstrates how to save and restore a client nexus.
        /// The test results have a display of the serialized JSON objects.
        /// </summary>
        [TestMethod]
        public void SerializeAndRestore()
        {
            JazzSerializer json = JazzSerializer.CreateSerializer();
            IEnumerable<jObject> jazzObjects;
            using (ClientNexus nexus = ClientNexus.Create())
            {
                MySimpleJazzClass red = new MySimpleJazzClass() { Color = "red" };
                MySimpleJazzClass blue = new MySimpleJazzClass() { Color = "blue" };
                nexus.Bind(red);
                nexus.Bind(blue);

                jazzObjects = nexus.Cache.OfType<jObject>();
            }

            string js = json.Serialize(jazzObjects);
            Console.WriteLine(js);
            //
            // restore
            //
            NexusConfig config = new NexusConfig()
            {
                BindUnits = json.Deserialize(js).ToArray(),
            };
            // check to insure everything is there
            Assert.AreEqual(0, json.NotDeserialized().Length);
            using (ClientNexus nexus = ClientNexus.Create(config))
            {
                jazzObjects.Foreach (j => Assert.IsTrue(nexus.Cache.Contains(j.ID)));
                //
                // Compare the original and restored client nexus
                //
                jObject[] originalObjs = jazzObjects.ToArray();
                jObject[] restoredObjs = nexus.Cache.OfType<jObject>().ToArray();
                string[] errors = originalObjs.DeepCompare(restoredObjs).ToArray();
                Assert.AreEqual(0, errors.Length, "Compare Error --->" + string.Join("\n\r", errors));
            }
        }
        
        #endregion

        #region AlternateSerializeAndPopulate_SingleObject
        /// <summary>
        /// Demonstrates how to save and restore jazz objects where only
        /// the Jazz base fields are saved and restored.
        /// The Jazz object, when restoring, must be separately created.
        /// The rest of the Jazz object must be seperately restored.
        /// </summary>
        [TestMethod]
        public void AlternateSerializeAndPopulate_SingleObject()
        {
            JazzBaseFieldSerializer serializer = JazzSerializer.CreateSerializerForBaseFieldsOnly();
            IEnumerable<jObject> jazzObjects;
            string redJson;
            string blueJson;
            string workspace;
            string workspaceEmpty;
            using (ClientNexus nexus = ClientNexus.Create())
            {
                MySimpleJazzClass red = new MySimpleJazzClass() { Color = "red" };
                MySimpleJazzClass blue = new MySimpleJazzClass() { Color = "blue" };
                red.Complete();  // change state 
                nexus.Bind(red);
                nexus.Bind(blue);
                // serialize objects
                redJson = red.JsonSerializeJazzBase(serializer);
                blueJson = blue.JsonSerializeJazzBase(serializer);
                // 'red' and 'blue' both reference the workspace object.
                workspace = nexus.PublicWorkspace.JsonSerializeJazzBase(serializer);
                workspaceEmpty = nexus.PublicWorkspace.Class.EmptyInstance.JsonSerializeJazzBase(serializer);
                jazzObjects = new jObject[] { red, blue};
            }

            Console.WriteLine("note: only Jazz base fields are in the JSON text");
            Console.WriteLine(redJson);
            Console.WriteLine(blueJson);
            //
            // restore -- note - "States" are restored.
            //
            {
                serializer.Clear();
                MySimpleJazzClass red = (MySimpleJazzClass)FormatterServices.GetUninitializedObject(typeof(MySimpleJazzClass));
                Assert.IsNull(red.Color);
                red.Color = "red"; // need to restore non-base jazz fields
                red.PopulateJazzBase(redJson, serializer);
                MySimpleJazzClass blue = (MySimpleJazzClass)FormatterServices.GetUninitializedObject(typeof(MySimpleJazzClass));
                Assert.IsNull(blue.Color);
                blue.Color = "blue";// need to restore non-base jazz fields
                blue.PopulateJazzBase(blueJson, serializer);

                // need to restore workspaces - blank workspace objects where created when 'red' and 'blue' were populated
                jWorkspace ws = (jWorkspace)serializer.Service.Create(jWorkspace.PublicID, typeof(jWorkspace));
                jWorkspace wsEmpty = (jWorkspace)serializer.Service.Create(jWorkspace.EmptyID, typeof(jWorkspace));
                ws.PopulateJazzBase(workspace, serializer);
                wsEmpty.PopulateJazzBase(workspaceEmpty, serializer);

                NexusConfig config = new NexusConfig()
                {
                    BindUnits = new IjStorageUnit[] { red, blue, ws, wsEmpty },
                };
                using (ClientNexus nexus = ClientNexus.Create(config))
                {
                    jazzObjects.Foreach(j => Assert.IsTrue(nexus.Cache.Contains(j.ID)));
                    //
                    // Compare the original and restored client nexus
                    //
                    jObject[] originalObjs = jazzObjects.ToArray();
                    jObject[] restoredObjs = jazzObjects.Select(j => nexus.Cache.GetUnit<jObject>(j.ID)).ToArray();
                    string[] errors = originalObjs.DeepCompare(restoredObjs).ToArray();
                    Assert.AreEqual(0, errors.Length, "Compare Error --->" + string.Join("\n\r", errors));
                }
            }
        }

        #endregion
        #region AlternateSerializeAndRestore_SingleObject
        /// <summary>
        /// Demonstrates how to save and restore jazz objects where only
        /// the Jazz base fields are saved and restored.
        /// The rest of the Jazz object must be seperately restored.
        /// </summary>
        [TestMethod]
        public void AlternateSerializeAndRestore_SingleObject()
        {
            JazzBaseFieldSerializer serializer = JazzSerializer.CreateSerializerForBaseFieldsOnly();
            IEnumerable<jObject> jazzObjects;
            string redJson;
            string blueJson;
            string wsJson;
            string wsEmptyJson;
            using (ClientNexus nexus = ClientNexus.Create())
            {
                MySimpleJazzClass red = new MySimpleJazzClass() { Color = "red" };
                MySimpleJazzClass blue = new MySimpleJazzClass() { Color = "blue" };
                red.Complete();  // change state 
                nexus.Bind(red);
                nexus.Bind(blue);
                redJson = red.JsonSerializeJazzBase(serializer);
                blueJson = blue.JsonSerializeJazzBase(serializer);
                wsJson = nexus.PublicWorkspace.JsonSerializeJazzBase(serializer);
                wsEmptyJson = nexus.PublicWorkspace.Class.EmptyInstance.JsonSerializeJazzBase(serializer);
                jazzObjects = new jObject[] { red, blue };
            }

            Console.WriteLine("note: only Jazz base fields are in the JSON text");
            Console.WriteLine(redJson);
            Console.WriteLine(blueJson);
            //
            // restore -- note - "States" are restored.
            //
            {
                MySimpleJazzClass red = (MySimpleJazzClass)JsonServices.Deserialize(redJson, serializer);
                Assert.IsNull(red.Color);
                red.Color = "red"; // need to restore non-base jazz fields
                MySimpleJazzClass blue = (MySimpleJazzClass)JsonServices.Deserialize(blueJson, serializer);
                Assert.IsNull(blue.Color);
                blue.Color = "blue";// need to restore non-base jazz fields
                jWorkspace ws = (jWorkspace)JsonServices.Deserialize(wsJson, serializer);
                jWorkspace wsEmpty = (jWorkspace)JsonServices.Deserialize(wsEmptyJson, serializer);

                NexusConfig config = new NexusConfig()
                {
                    BindUnits = new IjStorageUnit[] { red, blue, ws, wsEmpty },
                };

                using (ClientNexus nexus = ClientNexus.Create(config))
                {
                    jazzObjects.Foreach(j => Assert.IsTrue(nexus.Cache.Contains(j.ID)));
                    //
                    // Compare the original and restored client nexus
                    //
                    jObject[] originalObjs = jazzObjects.ToArray();
                    jObject[] restoredObjs = jazzObjects.Select(j => nexus.Cache.GetUnit<jObject>(j.ID)).ToArray();
                    string[] errors = originalObjs.DeepCompare(restoredObjs).ToArray();
                    Assert.AreEqual(0, errors.Length, "Compare Error --->" + string.Join("\n\r", errors));
                }
            }
        }

        #endregion


        #region MySimpleJazzClass
        /// <summary>
        /// 
        /// </summary>
        [Jazz]
        public class MySimpleJazzClass : jObject
        {
            public string Color { get; set; }
            public void Complete()
            {
                this.EnterState("Completed");
            }
            [StartState]
            void Start() { }
            [FinalState]
            void Completed() { }
        }
        #endregion
    }
}
